﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Windows;
using System.Windows.Controls;
using Babylon.Animations;
using Babylon.Animations.Skeleton;
using Babylon.Animations.Skeleton.Serialization;
using Babylon.Toolbox;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Silverlight;
using SStuff.XnaInterop;

namespace Babylon.Toolkit.SkeletonAnimationsSample
{
    public partial class MainPage : UserControl
    {
        private OrbitCamera _camera;

        public MainPage()
        {
            InitializeComponent();
            _camera = new OrbitCamera();
            _camera.FarPlane = 100000;
            _camera.NearPlane = 0.1f;
            _camera.Radius = 150;
            _camera.Target = new Vector3(0, 60, 0);
            _camera.AttachTo(inputSurface);
            _lightDir0.Normalize();
            _lightDir1.Normalize();
            _lightDir2.Normalize();
        }


        private Vector3 _lightDir0 = new Vector3(0.7f, -0.5f, -0.7f);

        public Vector3 LightDir0
        {
            get { return _lightDir0; }
            set { _lightDir0 = value; }
        }

        private Vector3 _lightDir1 = new Vector3(-0.7f, -0.5f, -0.7f);

        public Vector3 LightDir1
        {
            get { return _lightDir1; }
            set { _lightDir1 = value; }
        }

        private Vector3 _lightDir2 = new Vector3(0, -0.5f, 0.7f);

        public Vector3 LightDir2
        {
            get { return _lightDir2; }
            set { _lightDir2 = value; }
        }

        private void OnAspectRatioChanged(object sender, SizeChangedEventArgs e)
        {
            _camera.AspectRatio = e.NewSize.AspectRatio();
        }

        private Model _babyDude;
        private Babylon.Animations.Skeleton.SkinningAnimationPlayer _animPlayer;
        private AnimationClip _animationClip;

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            var gd = GraphicsDeviceManager.Current.GraphicsDevice;
            var dudeStream = Application.GetResourceStream(new Uri("Models/dude.bin", UriKind.Relative)).Stream;
            var dudeAnimStream = Application.GetResourceStream(new Uri("Models/dude_anim.json", UriKind.Relative)).Stream;
            var dude = InteropModel.FromBinaryReader(new System.IO.BinaryReader(dudeStream));
            dude.Prepare(gd);
            _babyDude = dude.ToBabylonModel(gd, (m, p) =>
            {
                var skinnedEffect = new SkinnedEffect(gd);
                skinnedEffect.SceneAmbientColor = new Color(0.2f, 0.2f, 0.2f, 0.2f);
                skinnedEffect.AmbientColor = new Color(0.2f, 0.2f, 0.2f, 0.2f);
                skinnedEffect.SpecularColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);
                skinnedEffect.SpecularPower = 20;
                skinnedEffect.Shininess = 0.3f;
                skinnedEffect.DiffuseColor = new Color(0.7f,0.7f,0.7f,1.0f);
                skinnedEffect.DiffuseTexture = p.IndexedTextureUsages["DiffuseTexture"].SL5Texture;
                skinnedEffect.BumpTexture = p.IndexedTextureUsages["BumpTexture"].SL5Texture;
                skinnedEffect.InvertBinormal = true;
                skinnedEffect.LightDir0 = _lightDir0;
                skinnedEffect.LightDir1 = _lightDir1;
                skinnedEffect.LightDir2 = _lightDir2;
                return skinnedEffect;
            });
            DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(SkinningData));
            SkinningData skinningData = s.ReadObject(dudeAnimStream) as SkinningData;
            _animPlayer = new SkinningAnimationPlayer(skinningData.SkeletonHierarchy, skinningData.BindPose, skinningData.InverseBindPose);
            _animationClip = new AnimationClip(_animPlayer.BoneTransforms.Length, skinningData.AnimationClips.Values.First().KeyFrames);

           
        }

        private void OnDraw(object sender, DrawEventArgs e)
        {
            if(_animPlayer.AnimState != AnimationState.Running)
                _animPlayer.StartAnimation(_animationClip, Matrix.Identity, (float) e.TotalTime.TotalSeconds);
            else
            {
                _animPlayer.UpdateAnimation(Matrix.Identity, (float)e.TotalTime.TotalSeconds);
            }
            var gd = e.GraphicsDevice;
            gd.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, new Color(0,0,0,255), 1,0 );
            _babyDude.Device = gd;
            Matrix world = Matrix.Identity;

            

            var skinData = _animPlayer.SkinTransforms;

            //for (int i = 0; i < skinData.Length;i++ )
            //    skinData[i] = Matrix.Identity;

                foreach (var mesh in _babyDude.Meshes)
                {
                    foreach (var effect in mesh.Effects)
                    {
                        var se = effect as SkinnedEffect;
                        se.Device = gd;
                        se.World = Matrix.Identity;
                        se.View = _camera.View;
                        se.Projection = _camera.Projection;
                        se.BonesSkin = skinData;
                        se.CameraPosition = _camera.Position;
                    }

                }

            _babyDude.Draw();

            _camera.ApplyInertia();
            e.InvalidateSurface();
        }
    }
}
